package com.xinchili.autoddl.autoClass.resolver;

import java.util.List;

import java.util.*;
import com.baomidou.mybatisplus.annotation.TableField;
import com.xinchili.autoddl.autoClass.properties.EntityScanProperties;
import com.xinchili.autoddl.autoClass.resolver.strategy.*;
import com.xinchili.autoddl.autoClass.util.CommontUtil;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;

import javax.validation.constraints.Size;
import java.io.IOException;
import java.lang.reflect.Field;

public abstract class AbstractDdlLogic extends AbstractDdlResolverSon implements
        ColumnNameLogic,
        ColumnTypeLogic,
        TableCommentLogic,
        ColumnCommentLogic,
        ScanLogic {

    private static final Logger log = LoggerFactory.getLogger(AbstractDdlLogic.class);

//    @Override
//    public Set<Class<?>> scanLogic(EntityScanProperties entityScanProperties) throws IOException {
//
//        //扫描等级 123
//        Integer scanLevel = entityScanProperties.getScanLevel();
//        //包路径集合例如（/**/entity）然后扫描entity下面的所有的，
//        List<String> tablePackage = entityScanProperties.getTablePackage();
//
////      扫描等级分为123
////      默认为1 当扫描等级为1的时候，则扫描entity下的所有类，
////      当扫描等级为2的时候，则只扫描返回默认entity下的所有类的 lombok.Data
////      当扫描等级为3的时候，则只扫描返回默认entity下的所有类的 lombok.Data && com.baomidou.mybatisplus.annotation.TableName
//
//
//        Set<Class<?>> classes = new HashSet<>();
//
//        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
//        SimpleMetadataReaderFactory factory = new SimpleMetadataReaderFactory();
//
//        try {
//            // 扫描整个classpath下的所有class文件
//            org.springframework.core.io.Resource[] resources =
//                    resolver.getResources("classpath*:/**/*.class");
//
//            for (org.springframework.core.io.Resource resource : resources) {
//                try {
//                    if (resource == null) {
//                        continue;
//                    }
//
//                    MetadataReader reader = factory.getMetadataReader(resource);
//                    if (reader == null) {
//                        continue;
//                    }
//
//                    AnnotationMetadata metadata = reader.getAnnotationMetadata();
//                    if (metadata == null) {
//                        continue;
//                    }
//
//                    String className = metadata.getClassName();
//                    if (className == null || className.isEmpty()) {
//                        continue;
//                    }
//
//                    // 检查是否为实体类（路径包含.entity.或.domain.）
//                    if (className.contains(".entity.")) {
//                        try {
//                            Class<?> clazz = Class.forName(className);
//                            if (clazz != null) {
//                                classes.add(clazz);
//                            }
//                        } catch (ClassNotFoundException | NoClassDefFoundError e) {
//                            // 记录日志但不中断执行
////                            System.err.println("Failed to load class: " + className + ", error: " + e.getMessage());
//                            log.error("Failed to load class: " + className + ", error: " + e.getMessage());
//                        } catch (Exception e) {
//                            // 记录其他异常
////                            System.err.println("Unexpected error loading class: " + className + ", error: " + e.getMessage());
//                            log.error("Unexpected error loading class: " + className + ", error: " + e.getMessage());
//                        }
//                    }
//                } catch (Exception e) {
//                    // 记录日志或处理异常，但不中断整个扫描过程

    /// /                    System.err.println("Failed to read resource: " + (resource != null ? resource.getDescription() : "null")
    /// /                            + ", error: " + e.getMessage());
//                    log.error("Failed to read resource: " + (resource != null ? resource.getDescription() : "null")
//                            + ", error: " + e.getMessage());
//                }
//            }
//        } catch (Exception e) {
//
//          System.err.println("Failed to scan classpath for entities: " + e.getMessage());
//            log.error("Failed to scan classpath for entities: " + e.getMessage());
//            throw e;
//        }
//
//        return classes;
//    }
    /**
     * 扫描符合条件的实体类
     * 根据扫描等级和包路径配置，扫描classpath下的类文件并根据注解过滤
     *
     * @param entityScanProperties 实体扫描配置属性
     * @return 符合条件的Class集合
     * @throws IOException 资源读取异常
     */
    @Override
    public Set<Class<?>> scanLogic(EntityScanProperties entityScanProperties) throws IOException {
        // 获取扫描等级配置（1-5级）
        Integer scanLevel = entityScanProperties.getScanLevel();

        // 获取指定的包路径列表，用于限定扫描范围
        List<String> tablePackage = entityScanProperties.getTablePackage();

        // 创建用于存储扫描到的类的集合
        Set<Class<?>> classes = new HashSet<>();

        // 创建资源解析器，用于扫描classpath下的资源
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

        // 创建元数据读取工厂，用于读取类的注解信息而不需要加载类
        SimpleMetadataReaderFactory factory = new SimpleMetadataReaderFactory();

        try {
            // 根据扫描等级决定扫描范围
            String[] resourcePatterns;

            // 等级3和5只扫描指定包路径下的类
            if (scanLevel == 3 || scanLevel == 5) {
                if (tablePackage != null && !tablePackage.isEmpty()) {
                    // 将包路径转换为资源模式（如: com.example.entity -> classpath*:com/example/entity/**/*.class）
                    resourcePatterns = tablePackage.stream()
                            .map(pkg -> "classpath*:" + pkg.replace(".", "/") + "/**/*.class")
                            .toArray(String[]::new);
                } else {
                    // 如果没有指定包路径，则默认扫描所有entity包下的类
                    resourcePatterns = new String[]{"classpath*:/**/*entity/**/*.class"};
                }
            } else {
                // 等级1,2,4扫描所有entity包下的类
                resourcePatterns = new String[]{"classpath*:/**/*entity/**/*.class"};
            }

            // 遍历所有资源模式进行扫描
            for (String pattern : resourcePatterns) {
                // 根据模式获取匹配的资源（.class文件）
                org.springframework.core.io.Resource[] resources = resolver.getResources(pattern);

                // 遍历所有找到的资源
                for (org.springframework.core.io.Resource resource : resources) {
                    try {
                        // 资源为空则跳过
                        if (resource == null) {
                            continue;
                        }

                        // 读取资源的元数据（包含类名和注解信息）
                        MetadataReader reader = factory.getMetadataReader(resource);
                        if (reader == null) {
                            continue;
                        }

                        // 获取注解元数据
                        AnnotationMetadata metadata = reader.getAnnotationMetadata();
                        if (metadata == null) {
                            continue;
                        }

                        // 获取类的全限定名
                        String className = metadata.getClassName();
                        if (className == null || className.isEmpty()) {
                            continue;
                        }

                        // 检查类是否在允许的包路径下
                        if (!isInAllowedPackages(className, tablePackage)) {
                            continue;
                        }

                        // 标记是否应该添加此类到结果集合
                        boolean shouldAdd = false;

                        // 根据扫描等级决定是否添加此类
                        switch (scanLevel) {
                            case 1:
                                shouldAdd = className.contains(".entity.");
                                break;

                            case 2:
                            case 3:
                                // 扫描等级为2/3时，只添加有lombok.Data注解的类
                                if (metadata.hasAnnotation("lombok.Data")) {
                                    shouldAdd = true;
                                }
                                break;

                            case 4:
                            case 5:
                                // 扫描等级为4/5时，只添加同时有lombok.Data和TableName注解的类
                                if (metadata.hasAnnotation("lombok.Data")
                                        && metadata.hasAnnotation("com.baomidou.mybatisplus.annotation.TableName")) {
                                    shouldAdd = true;
                                }
                                break;

                            default:
                                // 默认情况添加所有类
                                shouldAdd = true;
                                break;
                        }

                        // 如果符合条件则尝试加载类并添加到集合
                        if (shouldAdd) {
                            try {
                                // 通过类名加载类对象
                                Class<?> clazz = Class.forName(className);
                                if (clazz != null) {
                                    classes.add(clazz);
                                }
                            } catch (ClassNotFoundException | NoClassDefFoundError e) {
                                // 记录类加载失败的日志但不中断执行
                                log.error("Failed to load class: " + className + ", error: " + e.getMessage());
                            } catch (Exception e) {
                                // 记录其他异常
                                log.error("Unexpected error loading class: " + className + ", error: " + e.getMessage());
                            }
                        }
                    } catch (Exception e) {
                        // 记录资源读取异常，但不中断整个扫描过程
                        log.error("Failed to read resource: " + (resource != null ? resource.getDescription() : "null")
                                + ", error: " + e.getMessage());
                    }
                }
            }
        } catch (Exception e) {
            // 记录扫描过程中的严重异常并抛出
            log.error("Failed to scan classpath for entities: " + e.getMessage());
            throw e;
        }

        // 返回扫描到的所有符合条件的类
        return classes;
    }


    /**
     * 检查类是否在允许的包路径下
     *
     * @param className       类名
     * @param allowedPackages 允许的包路径列表
     * @return 是否在允许的包路径下
     */
    private boolean isInAllowedPackages(String className, List<String> allowedPackages) {

        String projectRoot = System.getProperty("user.dir");
        // 如果没有指定包路径，则默认允许所有entity类
        if (allowedPackages == null || allowedPackages.isEmpty()) {
            return className.startsWith(projectRoot);
        }

        // 检查类是否在指定的包路径下
        for (String pkg : allowedPackages) {
            if (className.startsWith(pkg)) {
                return true;
            }
        }

        return false;
    }


    /**
     * 获取字段对应的数据库列名
     *
     * @param field
     * @return 数据库列名
     */
    @Override
    public String resolveColumnName(Field field) {
        TableField anno = field.getAnnotation(TableField.class);
        if (anno != null && !anno.exist()) return null;
        if (anno != null && !anno.value().isEmpty()) return anno.value();
        return CommontUtil.camelToUnderline(field.getName());
    }

    /**
     * 根据字段的属性来确定数据的字段类型
     *
     * @param field 字段的属性结构
     * @return 数据库类型
     */
    @Override
    public String resolveColumnType(Field field) {
        Class<?> type = field.getType();

        if (type.equals(String.class)) {
            Size sizeAnno = field.getAnnotation(Size.class);
            if (sizeAnno != null && sizeAnno.max() > 65535) {
                return "LONGTEXT";
            } else if (sizeAnno != null && sizeAnno.max() > 255) {
                return "TEXT";
            } else {
                int maxLength = sizeAnno == null ? 255 : sizeAnno.max();
                return "VARCHAR(" + Math.min(maxLength, 255) + ")";
            }
        }

        return sqlTypes.getOrDefault(type, "varchar(255)");
    }

    /**
     * 获取类上的ApiModel注解的value值作为表注释
     *
     * @param clazz 类加载文件
     * @return 表COMMENT注释
     */
    @Override
    public String resolveTableComment(Class<?> clazz) {
        ApiModel anno = clazz.getAnnotation(ApiModel.class);
        return anno != null ? anno.value() : "";
    }


    /**
     * 获取他的属性的Value值作为注释
     *
     * @param field
     * @return 列COMMENT注释
     */
    @Override
    public String resolveColumnComment(Field field) {
        ApiModelProperty anno = field.getAnnotation(ApiModelProperty.class);
        return anno != null ? anno.value() : "";
    }


}